﻿#region Copyright - edgecase software

/*
Copyright 2009-2015 edgecase software - http://www.edgecasesoftware.com/opensource
 
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in 
compliance with the License. You may obtain a copy of the License at
 
     http://www.apache.org/licenses/LICENSE-2.0
 
Unless required by applicable law or agreed to in writing, software distributed under the License is 
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

See the License for the specific language governing permissions and limitations under the License.
*/

#endregion

namespace Turing
{
    public class RecursiveTuring : ITuringMachine
    {
        #region ITuringMachine Members

        public void Start(TransitionTable table)
        {
            if (table == null) return;

            CurrentTable = table;

            do
            {
                IsProcessing = true;
            }
            while (IsProcessing);
        }

        public void Stop()
        {
            IsProcessing = false;
        }

        public bool IsProcessing { get; private set; }

        public TransitionTable CurrentTable { get; private set; }

        #endregion

        /// <summary>
        /// Recursively processes the list of instructions for <see cref="CurrentTable"/>.
        /// </summary>
        /// <param name="instruction"><see cref="Instruction"/> to process.  If <see cref="EmptyInstruction"/>, the method returns.</param>
        protected virtual void ProcessInstruction(Instruction instruction)
        {
            if (instruction is EmptyInstruction || !IsProcessing)
            {
                return;
            }

            Instruction nextInstruction = GetNextAction(instruction);
            ProcessInstruction(nextInstruction);
        }

        /// <summary>
        /// Processess <param name="current" /> and returns it's value to the caller.
        /// </summary>
        /// <param name="current">Current <see cref="Instruction"/> to execute..</param>
        /// <returns>An <see cref="Instruction"/> as the next piece to process, <see cref="EmptyInstruction"/> if an exception takes place.</returns>
        protected virtual Instruction GetNextAction(Instruction current)
        {
            Instruction nextInstruction;

            try
            {
                nextInstruction = current.Process(this);
            }
            catch
            {
                nextInstruction = SingletonInstruction<EmptyInstruction>.Default;
            }

            return nextInstruction;
        }
    }
}